package com.mfs.proxy.client.transfer.http.response;

import com.mfs.common.enums.CompressEnum;
import com.mfs.common.utills.StringUtil;
import com.mfs.proxy.client.transfer.http.ByteBufferUtil;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.zip.GZIPOutputStream;

/**
 * Http 响应体
 *
 * @author mfs
 * @date 2023/7/18 23:03
 **/
public class HttpResponseBody {
    /**
     * HTTP响应
     * */
    private HttpResponse httpResponse;
    /**
     * 请求体字节
     * */
    private byte[] bytes = new byte[0];

    /**
     * 请求体是否完整,chunked 编码时有效
     * */
    private boolean completed = false;

    public HttpResponseBody(HttpResponse httpResponse) {
        this.httpResponse = httpResponse;
    }

    public CompressEnum getContentEncoding() {
        return httpResponse != null ? httpResponse.getCompress() : null;
    }

    public String getContentType() {
        return httpResponse.getHttpResponseHeader().getHead("content-type");
    }

    public Charset getCharset() {
        return httpResponse.getBodyCharset();
    }

    public boolean isChunked() {
        return httpResponse.isChunkedBlock() || httpResponse.getHttpResponseHeader().getHead("transfer-encoding").toLowerCase().equals("chunked");
    }

    public boolean isChunkedBlock() {
        return httpResponse.isChunkedBlock();
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }

    public boolean isCompleted() {
        return completed;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }

    /**
     *
     * 响应体是否可解码
     */
    public boolean enableBodyDecode() {
        String contentType = getContentType().toLowerCase();
        return StringUtil.isNotEmpty(contentType) && (contentType.contains("text/") || contentType.contains("application/json"));
    }


    @Override
    public String toString() {
        // chunked 块不进行解码
        if (isChunkedBlock()) {
            return null;
        }
        ByteBuffer wrap = ByteBuffer.wrap(bytes);
        byte[] aLine = null;
        int i = 0;

        byte[] body = new byte[0];
        while ((aLine = ByteBufferUtil.getALine(wrap)) != null) {
            if (isChunked() && i % 2 == 0) {
                i ++;
                continue;
            }
            i ++;
            byte[] newBody = new byte[body.length + aLine.length - 2];
            System.arraycopy(body, 0, newBody, 0, body.length);
            System.arraycopy(aLine, 0, newBody, body.length, aLine.length - 2);
            body = newBody;
        }
        body = getContentEncoding().getDecompressor().apply(body);
        return new String(body, getCharset());
    }

    public void setBody(String newBody) {
        if (isChunkedBlock()) {
            return;
        }
        byte[] bytes = getContentEncoding().getCompressor().apply(newBody.getBytes(getCharset()));
        if (isChunked()) {
            byte[] dataLength = (Integer.toHexString(bytes.length) + "\r\n").getBytes(getCharset());
            byte[] newBytes = new byte[dataLength.length + bytes.length + 7];
            System.arraycopy(dataLength, 0, newBytes, 0, dataLength.length);
            System.arraycopy(bytes, 0, newBytes, dataLength.length, bytes.length);
            System.arraycopy("\r\n0\r\n\r\n".getBytes(), 0, newBytes, dataLength.length + bytes.length, 7);
            bytes = newBytes;
        }
        this.bytes = bytes;
    }
}
